package com.linkgie.galaxyframework.security;

import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.linkgie.galaxyframework.organization.Organization;
import com.linkgie.galaxyframework.utils.RuntimeStatus;
import com.linkgie.galaxyframework.utils.service.ServiceContext;

/**
 * 提供对安全上下文的一些关键状态的访问；
 * 
 * @author huanghaiquan
 *
 */
public final class SecurityAssist {

	public static Logger LOGGER = LoggerFactory.getLogger(SecurityAssist.class);

	private static final SecurityContextSPI SECURITY_CONTEXT_SPI;

	static {
		ServiceContext<SecurityContextSPI> context = ServiceContext.load(SecurityContextSPI.class);
		if (context.getSize() == 0 || context.getSize() > 1) {
			throw new ApplicationSecurityException(RuntimeStatus.ILLEGAL_RUNTIME_CONTEXT, "非法的运行时上下文");
		}
		SECURITY_CONTEXT_SPI = context.getServices().iterator().next();
	}

	/**
	 * 当前登录Id；
	 * 
	 * @return
	 */
	public static long getLoginId() {
		return SECURITY_CONTEXT_SPI.getContext().getLoginId();
	}
	
	/**
	 * 登录凭据名称；
	 * <p>
	 * 返回值与登录方式有关， 例如，以用户名密码登录时，返回的是用户名；
	 * 
	 * @return
	 */
	public static String getCredentialName() {
		return SECURITY_CONTEXT_SPI.getContext().getCredentialName();
	}
	
	/**
	 * 返回当前上下文已登录认证的账号；
	 */
	public static AccountPrincipal getAccountPrincipal() {
		return SECURITY_CONTEXT_SPI.getContext().getAccountPrincipal();
	}

	/**
	 * 返回当前上下文已登录认证的账号；
	 */
	public static AccountPrincipal tryGetAccountPrincipal() {
		return SECURITY_CONTEXT_SPI.getContext().tryGetAccountPrincipal();
	}


	/**
	 * 检查当前上下文是否为应用用户登录状态；
	 * 
	 * @return
	 */
	public static final boolean isOpenUserLogin() {
		return tryGetOpenUserDetails() != null;
	}

	/**
	 * 当前认证中登录的应用；
	 * <p>
	 * 如果当前认证账号没有应用用户身份，或者不是以应用用户身份登录，则返回 null ；
	 * <p>
	 * 如果当前上下文未认证，则引发异常 {@link ApplicationSecurityException}；
	 * 
	 * @return
	 */
	public static final OpenApplication getApplication() {
		return SECURITY_CONTEXT_SPI.getContext().getApplication();
	}
	
	/**
	 * 当前认证中登录的应用；
	 * <p>
	 * 如果当前认证账号没有应用用户身份，或者不是以应用用户身份登录，则返回 null ；
	 * <p>
	 * 如果当前上下文未认证，则返回 null；
	 * 
	 * @return
	 */
	public static final OpenApplication tryGetApplication() {
		return SECURITY_CONTEXT_SPI.getContext().tryGetApplication();
	}

	/**
	 * 当前认证中登录的应用用户详情；
	 * <p>
	 * 如果当前认证账号没有应用用户身份，或者不是以应用用户身份登录，则返回 null ；
	 * <p>
	 * 如果当前上下文未认证，则引发异常 {@link ApplicationSecurityException}；
	 * 
	 * @return
	 */
	public static final OpenUserDetails getOpenUserDetails() {
		return SECURITY_CONTEXT_SPI.getContext().getOpenUserDetails();
	}
	
	/**
	 * 当前认证中登录的应用用户详情；
	 * <p>
	 * 如果当前认证账号没有应用用户身份，或者不是以应用用户身份登录，则返回 null ；
	 * <p>
	 * 如果当前上下文未认证，则返回 null；
	 * 
	 * @return
	 */
	public static final OpenUserDetails tryGetOpenUserDetails() {
		return SECURITY_CONTEXT_SPI.getContext().tryGetOpenUserDetails();
	}


	/**
	 * 返回当前登录用户的账户上下文；
	 * 
	 * <p>
	 * 如果当前没有登录用户，则返回 null；
	 * 
	 * @return
	 */
	public static SecurityContext getContext() {
		return SECURITY_CONTEXT_SPI.getContext();
	}

	/**
	 * 当前是否为匿名用户；
	 * <p>
	 * 
	 * 注意：匿名用户是一种特殊的认证形式，此方法返回 false 时，并不必然等同于 {@link #getLoginId()} 有效 ；
	 * 
	 * @return
	 */
	public static boolean isAnonymous() {
		return SECURITY_CONTEXT_SPI.getContext().isAnonymous();
	}

	/**
	 * 是否已认证；
	 * <p>
	 * 
	 * 注：“已认证”并非必然地表示为具名用户的认证结果，还包括匿名用户的认证结果；<br>
	 * 即，有可能当 {@link #isAuthenticated()} 为 true 时， {@link #isAnonymous()} 为 true ，而
	 * {@link #getLoginId()} 为 null ；
	 * 
	 * @return
	 */
	public static boolean isAuthenticated() {
		return SECURITY_CONTEXT_SPI.getContext().isAuthenticated();
	}

	/**
	 * 返回当前上下文已登录认证的企业；
	 * <p>
	 * 如果当前已登录认证的账号没有登录任何关联企业（例如‘根账号’），引发异常 {@link ApplicationSecurityException}；
	 * 
	 */
	public static OrganizationPrincipal getOrganizationPrincipal() {
		return SECURITY_CONTEXT_SPI.getContext().getOrganizationPrincipal();
	}

	/**
	 * 返回当前上下文已登录认证的企业；
	 * <p>
	 * 如果当前已登录认证的账号没有登录任何关联企业（例如‘根账号’），则返回 null；
	 * 
	 */
	public static OrganizationPrincipal tryGetOrganizationPrincipal() {
		return SECURITY_CONTEXT_SPI.getContext().tryGetOrganizationPrincipal();
	}

	/**
	 * 获取已授权的组织列表；
	 */
	public static Set<Organization> getAuthorizedOrganizations() {
		return SECURITY_CONTEXT_SPI.getContext().getAuthorizedOrganizations();
	}

	/**
	 * 获取已授权的组织列表；
	 */
	public static Set<Organization> tryGetAuthorizedOrganizations() {
		return SECURITY_CONTEXT_SPI.getContext().tryGetAuthorizedOrganizations();
	}

}
